<?php
/**
 * Description: app端的视频广告管理
 * Author: hezhizheng
 * Date: 2018/6/19
 * Time: 14:22
 * Created by Created by Panxsoft.
 */

namespace App\Http\Controllers\Admin\Customer;

use App\Http\Controllers\ApiController;
use App\Http\Requests\Admin\Customer\Advert\AdvertIndexRequest;
use App\Http\Requests\Admin\Customer\Advert\AdvertStoreRequest;
use App\Http\Requests\Admin\Customer\Advert\AdvertUpdateRequest;
use App\Models\Admin\CustomerAdmin;
use App\Models\Customer\Advert;
use App\Models\Url;
use App\Services\Utils\Guard;
use App\Services\Utils\RequestParam;
use App\Services\Utils\Transaction;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;

class AdvertController extends ApiController
{
    const ROUTES = [
        'index'   => 'api.admin.customer.advert.index',
        'store'   => 'api.admin.customer.advert.store',
        'update'  => 'api.admin.customer.advert.update',
        'destroy' => 'api.admin.customer.advert.destroy',
    ];

    /**
     * @test
     *
     * @param AdvertIndexRequest $request
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function index(AdvertIndexRequest $request)
    {
        $this->checkCustomer();

        $this->checkIsTrue(CustomerAdmin::isGuardSuperAdmin(), trans('admin.is_super_man'));

        $customer = Guard::customer();

        $adverts = $customer->adverts()
            ->with([
                'customer'       => function (BelongsTo $builder) {
                    return $builder->select(['id', 'name']);
                },
                'advertType'     => function (BelongsTo $builder) {
                    return $builder->select(['id', 'name']);
                },
                'deviceAccounts' => function (BelongsToMany $builder) {
                    return $builder->select(['device_accounts.id', 'device_accounts.device_name', 'device_accounts.account']);
                },
            ])
            ->columnsKeywordsOrLike(['name' => $request->keyword])
            ->with('redirectable')
            ->latest()
            ->paginate($request->per_page ?: 15);

        return $this->response(compact('adverts'));
    }

    /**
     * @return array|\Illuminate\Http\Response
     */
    public function create()
    {
        $customer = Guard::customer();

        $bos_config = $this->getBosConfig();

        $store_devices = $customer->stores()
            ->has('deviceAccounts')
            ->with(['deviceAccounts' => function (HasMany $device_relation) {
                return $device_relation->select(['id', 'store_id', 'account', 'device_name']);
            }])
            ->get(['id', 'name']);

        return $this->response(compact('bos_config', 'store_devices'));
    }

    /**
     * @test
     *
     * @param AdvertStoreRequest $request
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function store(AdvertStoreRequest $request)
    {
        $this->checkCustomer();

        $this->checkIsTrue(CustomerAdmin::isGuardSuperAdmin(), trans('admin.is_super_man'));

        $store = Transaction::handle(function () use ($request) {

            /** @var Advert $advert */
            $advert = (new Advert)->create($this->assembleAdvert());

            $advert->deviceAccounts()->sync($request->device_account_ids);

            return $advert;
        });

        return $this->response(compact('store'));

    }

    /**
     * @test
     *
     * @param AdvertUpdateRequest $request
     * @param $id
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function update(AdvertUpdateRequest $request, $id)
    {
        $this->checkCustomer();

        $this->checkIsTrue(CustomerAdmin::isGuardSuperAdmin(), trans('admin.is_super_man'));

        /** @var Advert $advert */
        $advert = (new Advert)->where('customer_id', Guard::customerAdmin()->customer_id)
            ->find($id);
        $this->checkItemExist($advert, trans('admin.advert'));

        $update = Transaction::handle(function () use ($request, $advert) {
            $advert->destroyRedirectUrl();

            $update = $advert->update($this->assembleAdvert());

            $advert->deviceAccounts()->sync($request->device_account_ids);

            return $update;
        });

        return $this->response(compact('update'));
    }

    /**
     * @return array
     */
    private function assembleAdvert(): array
    {
        $default_data = [
            'customer_id' => Guard::customerAdmin()->customer_id,
        ];

        $data = RequestParam::normalize([
            'advert_type_id', 'name',
            'content_key', 'play_second',
            'redirectable_type', 'redirectable_id',
        ]);

        $data['redirectable_type'] = $data['redirectable_type'] ?? '';

        $data = $this->assembleRedirectUrl($data);

        $data = array_merge($default_data, $data);

        return $data;
    }


    /**
     * @test
     *
     * @param $id
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function destroy($id)
    {
        $this->checkCustomer();

        $this->checkIsTrue(CustomerAdmin::isGuardSuperAdmin(), trans('admin.is_super_man'));

        $advert = (new Advert)->where('customer_id', Guard::customerAdmin()->customer_id)
            ->find($id);
        $this->checkItemExist($advert, trans('admin.advert'));

        $delete = Transaction::handle(function () use ($advert) {
            $advert->destroyRedirectUrl();
            $advert->deviceAccounts()->sync([]);
            $delete = $advert->delete();
            return $delete;
        });

        return $this->response(compact('delete'));

    }

    /**
     *  返回bos的配置到前端，用来上传文件
     *
     * @return array
     */
    private function getBosConfig()
    {
        return [
            'prefix'          => 'advert/', // <- bos bucket
            'end_point'       => config('bos.config.endpoint'),
            'upload_max_size' => '100M',
            'bucket'          => config('bos.bucket'),
            // 线上如果 apache 是 https 请求， 反向代理到使用 http 的 docker 中
            // 直接调用 route() 函数返回的是 http，前端会报错，这里使用相对路径让前端自己处理
            'token_url'       => route('bos-token', [], false),
        ];
    }

    private function createNewUrl(string $url): Url
    {
        return (new Url)->create(compact('url'));
    }

    /**
     * @param array $data
     *
     * @return array
     */
    private function assembleRedirectUrl(array $data): array
    {
        if ($data['redirectable_type'] === class_basename(Url::class)) {
           $data['redirectable_id'] = $this->createNewUrl(request()->get('redirect_url'))->getKey();
        }

        return $data;
    }
}